package com.ungao.framework.executor;

import com.ungao.framework.mapping.Configuration;
import com.ungao.framework.mapping.MapperStatement;
import com.ungao.framework.parameter.ParameterHandler;
import com.ungao.framework.parse.sql.SqlTokenParser;
import com.ungao.framework.pool.MiniDataSource;
import com.ungao.framework.reflection.ReflectionUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class Executor {

    /**
     * 数据源
     */
    private MiniDataSource dataSource;

    public Executor(Configuration configuration) {
        this.dataSource = MiniDataSource.getInstance(configuration.getEnvironment());
    }

    /**
     * 新增
     *
     * @param mapperStatement
     * @param args
     * @return
     */
    public int insert(MapperStatement mapperStatement, Object[] args) {
        int insertRows = 0;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = this.dataSource.getConnection();
            preparedStatement = connection.prepareStatement(SqlTokenParser.parse(mapperStatement.getSql()));
            ParameterHandler parameterHandler = new ParameterHandler(preparedStatement);
            parameterHandler.setParameters(args);
            insertRows = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (null != resultSet) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != preparedStatement) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != connection) {
                this.dataSource.releaseConnection(connection);
            }
        }
        return insertRows;
    }

    /**
     * 删除
     *
     * @param mapperStatement
     * @param args
     * @return
     */
    public int delete(MapperStatement mapperStatement, Object[] args) {
        int deleteRows = 0;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = this.dataSource.getConnection();
            preparedStatement = connection.prepareStatement(SqlTokenParser.parse(mapperStatement.getSql()));
            ParameterHandler parameterHandler = new ParameterHandler(preparedStatement);
            parameterHandler.setParameters(args);
            deleteRows = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (null != resultSet) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != preparedStatement) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != connection) {
                this.dataSource.releaseConnection(connection);
            }
        }
        return deleteRows;
    }

    /**
     * 修改
     *
     * @param mapperStatement
     * @param args
     * @return
     */
    public int update(MapperStatement mapperStatement, Object[] args) {
        int updateRows = 0;
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = this.dataSource.getConnection();
            preparedStatement = connection.prepareStatement(SqlTokenParser.parse(mapperStatement.getSql()));
            ParameterHandler parameterHandler = new ParameterHandler(preparedStatement);
            parameterHandler.setParameters(args);
            updateRows = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (null != resultSet) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != preparedStatement) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != connection) {
                this.dataSource.releaseConnection(connection);
            }
        }
        return updateRows;
    }

    /**
     * 查询
     *
     * @param mapperStatement
     * @param args
     * @param <T>
     * @return
     */
    public <T> List<T> query(MapperStatement mapperStatement, Object[] args) {
        List<T> resultList = new ArrayList<>();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = this.dataSource.getConnection();
            preparedStatement = connection.prepareStatement(SqlTokenParser.parse(mapperStatement.getSql()));
            ParameterHandler parameterHandler = new ParameterHandler(preparedStatement);
            parameterHandler.setParameters(args);
            resultSet = preparedStatement.executeQuery();
            this.parseResultSet(resultSet, resultList, mapperStatement.getResultType());
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (null != resultSet) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != preparedStatement) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != connection) {
                this.dataSource.releaseConnection(connection);
            }
        }
        return resultList;
    }

    /**
     * 解析ResultSet
     *
     * @param resultSet
     * @param resultList
     * @param resultType
     * @param <T>
     */
    private <T> void parseResultSet(ResultSet resultSet, List<T> resultList, String resultType) {
        try {

            //获取Class对象
            Class<T> clazz = (Class<T>) Class.forName(resultType);

            //获得结果集结构信息、元数据.获得列数
            ResultSetMetaData metaData = resultSet.getMetaData();
            final int columnCount = metaData.getColumnCount();
            while (resultSet.next()) {
                T result = clazz.newInstance();
                for (int i = 1; i <= columnCount; i++) {
                    ReflectionUtils.setter(result, metaData.getColumnName(i), resultSet.getObject(i));
                }
                resultList.add(result);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
